#include "SimulationElement.h"


namespace OpenNano
{
    REGISTER_OBJECT_FACTORY( SimulationElement, SIMULATION_TAG );

    SimulationElement::SimulationElement(TiXmlElement * element) :
                            ConfigElement(element), logger(log4cplus::Logger::getInstance( SIMULATION_TAG )),
                            _scale(MICRO), _factor(1.0), _forces(), _objects(), _everything_is_good_so_far(true)
                    {
                    }

    SimulationElement::~SimulationElement()
    {
        _forces.clear();
        _objects.clear();
    }

    void SimulationElement::init()
    {
        LOG4CPLUS_INFO(logger, "Simulation element: initialized");
    }

    double SimulationElement::getChosenFactor()
    {
        return _factor;
    }

    ScaleOrder SimulationElement::getChosenScale()
    {
        return _scale;
    }

    const ForcesMap& SimulationElement::getForces() const
    {
        return _forces;
    }

    const ObjectsMap& SimulationElement::getObjects() const
    {
        return _objects;
    }

    ForceElement * SimulationElement::getForce(const std::string &name)
    {
        ForceElement * f(0);
        ForcesMap::iterator it = _forces.find(name);
        if ( it != _forces.end() )
        {
            f = it->second;
        }
        else
        {
            //attribute not recognized
            LOG4CPLUS_WARN(logger, "Force not found:");
            LOG4CPLUS_WARN(logger, name);
        }
        return f;
    }

    ObjectElement * SimulationElement::getObject(const std::string &name)
    {
        ObjectElement * o(0);
        ObjectsMap::iterator it = _objects.find(name);
        if ( it != _objects.end() )
        {
            o = it->second;
        }
        else
        {
            //attribute not recognized
            LOG4CPLUS_WARN(logger, "Object not found:");
            LOG4CPLUS_WARN(logger, name);
        }
        return o;
    }


    void SimulationElement::attributeFound(TiXmlAttribute * attribute)
    {
        if (    attribute->NameTStr().compare(SCALE_ATTRIBUTE) == 0 )
        {
           if ( attribute->ValueStr().compare(MICRO_VALUE) == 0 )
           {
               _scale = MICRO;
           }
           else if ( attribute->ValueStr().compare(NANO_VALUE) == 0 )
           {
               _scale = NANO;
           }
           else
           {
               //attribute not recognized
                LOG4CPLUS_WARN(logger, "Scale value not recognized:");
                LOG4CPLUS_WARN(logger, attribute->ValueStr());

                unknownAttributeFound(attribute);
                _everything_is_good_so_far=false;
               return;
           }

           // _version = attribute->DoubleValue();  //useless?
        }
        else if (    attribute->NameTStr().compare(FACTOR_ATTRIBUTE) == 0 &&
                attribute->QueryDoubleValue(&_factor)==TIXML_SUCCESS )
        {
            _factor = attribute->DoubleValue();  //useless?
        }
        else
        {
            //attribute not recognized
            LOG4CPLUS_WARN(logger, "Attribute not recognized:");
            LOG4CPLUS_WARN(logger, attribute->NameTStr());

            unknownAttributeFound(attribute);
            _everything_is_good_so_far=false;
        }
    }

    void SimulationElement::childElementFound( TiXmlElement * childElement )
    {
        if ( childElement->ValueStr().compare( FORCE_TAG ) == 0 )
        {
            ForceElement * _f = (ForceElement *)ConfigElementFactory::getInstance().create( FORCE_TAG )( childElement );
            if ( _f )
            {
                _everything_is_good_so_far=_f->process();
                if (_everything_is_good_so_far)
                {
                    _forces[_f->getName()] = _f;
                }
                else
                {
                    //throw a warning
                    delete _f;
                    LOG4CPLUS_ERROR(logger, "Force element not processed correctly");
                }
            }
            else
            {
                LOG4CPLUS_WARN(logger, "Force element not registered in the factory:");
                LOG4CPLUS_WARN(logger, childElement->ValueStr());

                unknownElementFound(childElement);
                _everything_is_good_so_far=false;
            }
        }
        else if ( childElement->ValueStr().compare( OBJECT_TAG ) == 0 )
        {
            ObjectElement * _o = (ObjectElement *)ConfigElementFactory::getInstance().create( OBJECT_TAG )( childElement );
            if ( _o )
            {
                _everything_is_good_so_far=_o->process();
                if (_everything_is_good_so_far)
                {
                    _objects[_o->getName()] = _o;
                }
                else
                {
                    //throw a warning
                    delete _o;
                    LOG4CPLUS_ERROR(logger, "Object element not processed correctly");

                }
            }
            else
            {
                LOG4CPLUS_WARN(logger, "Object element not registered in the factory:");
                LOG4CPLUS_WARN(logger, childElement->ValueStr());

                unknownElementFound(childElement);
                _everything_is_good_so_far=false;
            }
        }
        else
        {
            //Element not recognized
            LOG4CPLUS_WARN(logger, "Child element not recognized:");
            LOG4CPLUS_WARN(logger, childElement->ValueStr());

            unknownElementFound(childElement);
            _everything_is_good_so_far=false;
        }
    }

    void SimulationElement::textFound(const char * text)
    {
        LOG4CPLUS_WARN(logger, "Text not recognized:");
        LOG4CPLUS_WARN(logger, text);

        unknownTextFound(text);
    }

    bool SimulationElement::postConfiguration()
    {
        return _everything_is_good_so_far;
    }


}
